package com.mazong.serversecbasic.security;


import com.mazong.serversecbasic.mapper.IDbSecurityMapper;
import com.mazong.serversecbasic.pojo.TbRolePermisson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * TODO 拦截URL进行权限判断
 */
@Component
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    IDbSecurityMapper iDbSecurityMapper;

    private static HashMap<String, Collection<ConfigAttribute>> mapRoles = null;

    /**
     * 是否拦截
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(Class<?> aClass) {
        //web项目一般使用FilterInvocation来判断，或者直接返回true
        //return FilterInvocation.class.isAssignableFrom(aClass);
        return true;
    }

    /**
     * 此处方法如果做了实现，返回了定义的权限资源列表，
     * Spring Security会在启动时校验每个ConfigAttribute是否配置正确。
     * 如果不需要校验，这里实现方法，方法体直接返回null即可。
     * @return
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    /**
     * TODO 返回请求资源需要的角色，可以是多个权限
     * @param o
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        // object 中包含用户请求的request对象
        String requestUrl = ((FilterInvocation) o).getRequestUrl();
        log.info("requestUrl={}", requestUrl);

        //去数据库查询资源
        loadAllConfigAttributes();
        if(null == mapRoles || mapRoles.size()<=0) {
            // 数据库里没有任何权限设置，不管了
            return null;
        }

        // 根据请求url寻找权限
        HttpServletRequest request = ((FilterInvocation) o).getRequest();
        Iterator<String> it = mapRoles.keySet().iterator();
        while(it.hasNext()) {
            String url = it.next();
            if(new AntPathRequestMatcher(url).matches(request)) {
                log.info("ok,url="+url);
                return mapRoles.get(url);
            }
        }

        // 没有权限
        // 如果本方法返回null的话，意味着当前这个请求不需要任何角色就能访问
        // 此处做逻辑控制，如果没有匹配上的，返回一个默认具体权限，防止漏缺资源配置
        //log.info("当前访问路径是{},这个url所需要的访问权限是{}", requestUrl, "ROLE_LOGIN");
        //return SecurityConfig.createList("USER");
        return null;
    }

    public void loadAllConfigAttributes() {

        if(null != mapRoles) {
            return;
        }

        System.out.println("getAllConfigAttributes ...");
        mapRoles = new HashMap<>();
        List<TbRolePermisson> permissonList = iDbSecurityMapper.getRolePermissons();

        for(TbRolePermisson p : permissonList) {
            String url = p.getUrl();
            String roleName = p.getRoleName();
            log.info("url={},role={}", url, roleName);

            ConfigAttribute role = new SecurityConfig(roleName);
            if(mapRoles.containsKey(url)) {
                mapRoles.get(url).add(role);
            }
            else {
                List<ConfigAttribute> list = new ArrayList<>();
                list.add(role);
                mapRoles.put(url, list);
            }
        }
    }
}
